#include "Subsystems/SubsystemBlockEntities.h"

#include "Engine/Vector3.hpp"

#include "Network/Packages/MessagePackage.h"
#include "Network/Packages/EntityPackage.h"
#include "Network/PackageManager.h"

#include "Managers/GameManager.h"
#include "Managers/EntityManager.h"
#include "Managers/ComponentsManager.h"

#include "Components/ComponentBlockEntity.h"
#include "Components/ComponentBody.h"
#include <fstream>

#include "Log.h"
#include "GameSingleton.h"
#include "GameRegistry.hpp"
#include "GameThreadPool.hpp"
#include "Game/EntityData.hpp"

using namespace PocketSurvival::Engine;

namespace PocketSurvival
{
    /**
     * @brief 创建方块实体
     * @param jsonData 方块实体的基础数据
    */
    void SubsystemBlockEntities::createBlockEntity(const nlohmann::json& jsonData)
    {
        entt::entity entity = GameSingleton::entityManager->createEntityByEssentitalData(jsonData);

        ComponentBlockEntity **blockEntityPtr = GameSingleton::gameRegistry->try_get<ComponentBlockEntity*>(entity);
        if(blockEntityPtr == nullptr)
        {
            throw std::logic_error(fmt::format("添加的方块实体没有找到方块组件，实体名称: {}, 实体GUID: {}", jsonData["ObjectName"].get<std::string>(), jsonData["ObjectGuid"].get<std::string>()));
        }
        ComponentBlockEntity *blockEntity = *blockEntityPtr;

        // 这里锁的问题有点麻烦，先要查表，确定表里面对应的位置没有方块实体才能添加新的方块实体
        blockEntitiesMutex.lock();
        bool isFound = (m_blockEntitiesMap.find(blockEntity->coordinates) != m_blockEntitiesMap.end());
        blockEntitiesMutex.unlock();
        
        if(isFound == true)
        {
            Log::Warn(fmt::format("位置 {},{},{} 已经有方块实体存在了，不能重复添加", blockEntity->coordinates.posX,blockEntity->coordinates.posY,blockEntity->coordinates.posZ));
            GameSingleton::entityManager->destoryEntity(entity);
            return;
        }
        // 通知所有子系统，有新的实体添加
        // 这里的方块实体还没添加进表里面，所以有没有加锁倒是没啥问题
        for (auto &pair : GameSingleton::gameManager->subsystemMap)
        {
            pair.second->onEntityAdded(entity);
        }

        // 新添加的实体要告知所有客户端
        std::shared_ptr<EntityPackage> package = std::make_shared<EntityPackage>(entity, EntityPackageType::LoadOne);
        GameSingleton::packageManager->addSendPackageToQueue(package);

        // 位置表也加一下，方便查找
        blockEntitiesMutex.lock();
        m_blockEntitiesMap[blockEntity->coordinates] = blockEntity;
        blockEntitiesMutex.unlock();
    }

    /**
     * @brief 生成新的方块实体
     * @param entityName 实体名称
     * @param point 方块实体生成的位置
    */
    void SubsystemBlockEntities::addBlockEntity(const std::string &entityName, const Point3 &point)
    {
        BlockEntityData *blockEntityData = new BlockEntityData;
        blockEntityData->entityName = entityName;
        blockEntityData->point = point;
        m_addBlockEntityQueue.enqueue(blockEntityData);
    }
    
    /**
     * @brief 移除方块实体
     * @param blockEntity 方块实体的基本组件
     * @note Componets 组件都是附带 entity 的
    */
    void SubsystemBlockEntities::removeBlockEntity(ComponentBlockEntity* blockEntity)
    {
        if (blockEntity != nullptr)
        {
            m_removeBlockEntityQueue.enqueue(blockEntity);
        }
    }


    void SubsystemBlockEntities::update(float dt)
    {
        BlockEntityData *blockEntityData = nullptr;
        while(m_addBlockEntityQueue.try_dequeue(blockEntityData))
        {
            nlohmann::json essentialJson;
            if (GameSingleton::entityManager->tryGetEntityEssentialData(blockEntityData->entityName, essentialJson))
            {
                essentialJson["Components"]["BlockEntity"]["Coordinates"] = blockEntityData->point;
                createBlockEntity(essentialJson);
            }
            delete blockEntityData;
        }

        ComponentBlockEntity *componentBlockEntity = nullptr;
        while(m_removeBlockEntityQueue.try_dequeue(componentBlockEntity))
        {
            const Point3 &point = componentBlockEntity->coordinates;
            entt::entity removeEntity = componentBlockEntity->entity;

            // 子系统处理不需要查表，这里加不加锁无所谓了
            auto &subsystemMap = GameSingleton::gameManager->subsystemMap;
            for(auto &pair : subsystemMap)
            {
                pair.second->onEntityRemoved(removeEntity);
            }

            // 通知客户端有实体被移除了
            GameSingleton::packageManager->addSendPackageToQueue(std::make_shared<EntityPackage>(removeEntity, EntityPackageType::Remove));

            blockEntitiesMutex.lock();
            auto it = m_blockEntitiesMap.find(point);
            if (it != m_blockEntitiesMap.end())
            {
                m_blockEntitiesMap.erase(it);
            }
            else
            {
                Log::Warn(fmt::format("位置 {},{},{} 不存在方块实体，无法进行移除", point.posX, point.posY, point.posZ));
            }
            blockEntitiesMutex.unlock();

            GameSingleton::entityManager->destoryEntity(removeEntity);
        }
    }

    void SubsystemBlockEntities::internalSave()
    {
        nlohmann::json blockEntitiesJson = nlohmann::json::array();

        blockEntitiesMutex.lock();
        for(auto &pair : m_blockEntitiesMap)
        {
            nlohmann::json jsonData;
            EntityData *entityData = GameSingleton::gameRegistry->get<EntityData*>(pair.second->entity);
            jsonData["Name"] = entityData->ObjectName;
            GameSingleton::componentsManager->saveComponents(pair.second->entity, jsonData["Components"]);
            blockEntitiesJson.push_back(jsonData);
        }
        blockEntitiesMutex.unlock();
        
        std::string blockEntitiesFile = fmt::format("{}/BlockEntities.json", GameSingleton::gameManager->getNowWorldPath());
        if(Utils::SaveTextFile(blockEntitiesFile, blockEntitiesJson.dump()) == false)
        {
            // throw std::runtime_error(fmt::format("无法保存方块实体数据到文件: {}", blockEntitiesFile)); 
            Log::Error(fmt::format("无法保存方块实体数据到文件: {}", blockEntitiesFile));
        }
    }

    void SubsystemBlockEntities::load(const nlohmann::json &json)
    {
        std::string jsonText;
        if(Utils::LoadTextFile(fmt::format("{}/BlockEntities.json", GameSingleton::gameManager->getNowWorldPath()), jsonText) == true)
        {
            nlohmann::json blockEntitiesJson = nlohmann::json::parse(jsonText);
            for(const nlohmann::json &subJson : blockEntitiesJson)
            {
                nlohmann::json essentialJson;
                std::string entityName = subJson["Name"].get<std::string>();
                if(GameSingleton::entityManager->tryGetEntityEssentialData(entityName, essentialJson) == true)
                {
                    Log::Info(fmt::format("加载了方块实体 {}", entityName));
                    essentialJson["Components"].merge_patch(subJson["Components"]);
                    createBlockEntity(essentialJson);
                }
                else
                {
                    Log::Warn(fmt::format("没有找到实体 {} 的基础数据", entityName));
                }
            }
        }
    }

    void SubsystemBlockEntities::save(nlohmann::json &json)
    {
        // 交由线程池进行保存处理
        GameSingleton::gameSaveThreadPool->push_task(std::bind(&SubsystemBlockEntities::internalSave, this));
    }

    static const std::string subsystemName = "BlockEntities";
    const std::string& SubsystemBlockEntities::getName() const
    {
        return subsystemName;
    }
    SubUpdateType SubsystemBlockEntities::getUpdateType()
    {
        return SubUpdateType::MainSingleUpdate;
    }
    SubLoadEchelon SubsystemBlockEntities::getLoadEchelon()
    {
        return SubLoadEchelon::Tenth;
    }
}